package util

import "math"

type ByteStream struct{
	content []byte
	rdPtr int16
	wtPtr int16
}

func NewByteStream(bytes []byte)(*ByteStream){
	return &ByteStream{bytes, 0, 0}
}

func (stream *ByteStream) GetType()(t int16){
	stream.rdPtr = 2
	t = stream.ReadInt16()
	return
}

func (stream *ByteStream) MoveHead(){
	stream.wtPtr += 4
	return
}

func (stream *ByteStream) WriteHead(t int16){
	if len(stream.content) >= 4 {
		stream.content[0] = byte(stream.wtPtr-2)
		stream.content[1] = byte((stream.wtPtr-2)>>8)
		stream.content[2] = byte(t)
		stream.content[3] = byte(t>>8)
	}
	return
}

func (stream *ByteStream) Data()([]byte){
	return stream.content[0:stream.wtPtr]
}

func (stream *ByteStream) ReadByte()(ret byte){
	if stream.rdPtr < int16(len(stream.content)) {
		ret = stream.content[stream.rdPtr]
		stream.rdPtr++
	}
	return
}

func (stream *ByteStream) WriteByte(val byte){
	if stream.wtPtr < int16(len(stream.content)) {
		stream.content[stream.wtPtr] = val
		stream.wtPtr++	
	}
	return	
}

func (stream *ByteStream) ReadInt16()(ret int16) {
	for i := uint8(0); i < 2; i++ {
		ret |= int16(stream.ReadByte())<<(8*i)
	}
	return
}

func (stream *ByteStream) WriteInt16(val int16) {
	for i := uint8(0); i < 2; i++ {
		stream.WriteByte(byte(val>>(8*i)))
	}
	return
}

func (stream *ByteStream) ReadUint16()(ret uint16) {
	for i := uint8(0); i < 2; i++ {
		ret |= uint16(stream.ReadByte())<<(8*i)
	}
	return
}

func (stream *ByteStream) WriteUint16(val uint16) {
	for i := uint8(0); i < 2; i++ {
		stream.WriteByte(byte(val>>(8*i)))
	}
	return
}


func (stream *ByteStream) ReadInt32()(ret int32) {
	for i := uint8(0); i < 4; i++ {
		ret |= int32(stream.ReadByte())<<(8*i)
	}
	return
}

func (stream *ByteStream) WriteInt32(val int32) {
	for i := uint8(0); i < 4; i++ {
		stream.WriteByte(byte(val>>(8*i)))
	}
	return
}

func (stream *ByteStream) ReadUint32()(ret uint32) {
	for i := uint8(0); i < 4; i++ {
		ret |= uint32(stream.ReadByte())<<(8*i)
	}
	return
}

func (stream *ByteStream) WriteUint32(val uint32) {
	for i := uint8(0); i < 4; i++ {
		stream.WriteByte(byte(val>>(8*i)))
	}
	return
}

func (stream *ByteStream) ReadInt64()(ret int64) {
	for i := uint8(0); i < 8; i++ {
		ret |= int64(stream.ReadByte())<<(8*i)
	}
	return
}

func (stream *ByteStream) WriteInt64(val int64) {
	for i := uint8(0); i < 8; i++ {
		stream.WriteByte(byte(val>>(8*i)))
	}
	return
}

func (stream *ByteStream) ReadUint64()(ret uint64) {
	for i := uint8(0); i < 8; i++ {
		ret |= uint64(stream.ReadByte())<<(8*i)
	}
	return
}

func (stream *ByteStream) WriteUint64(val uint64) {
	for i := uint8(0); i < 8; i++ {
		stream.WriteByte(byte(val>>(8*i)))
	}
	return
}

func (stream *ByteStream) ReadFloat32()(ret float32) {
	ret = math.Float32frombits(stream.ReadUint32())
	return
}

func (stream *ByteStream) WriteFloat32(val float32) {
	stream.WriteUint32(math.Float32bits(val))
	return
}

func (stream *ByteStream) ReadFloat64()(ret float64) {
	ret = math.Float64frombits(stream.ReadUint64())
	return
}

func (stream *ByteStream) WriteFloat64(val float64) {
	stream.WriteUint64(math.Float64bits(val))
	return
}

func (stream *ByteStream) ReadString()(ret string) {
	bytes := make([]byte, stream.ReadInt16())
	for i, _ := range bytes {
		bytes[i] = stream.ReadByte()
	}
	ret = string(bytes)
	return
}

func (stream *ByteStream) WriteString(val string) {
	bytes := []byte(val)
	stream.WriteInt16(int16(len(bytes)))
	for _, v := range bytes {
		stream.WriteByte(v)
	}
	return
}